package Gestor;

import Clases.Aguinaldo;
import Clases.AguinaldoId;
import Clases.Liquidacion;
import Clases.Pago;
import java.sql.Date;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.Restrictions;

public class GestorPago extends GestorBase {

    private static GestorPago instancia = null;
    private static final String PAGO_CEDULA = "SP_SELECCIONAR_PAGO_POR_CEDULA";
    private static final String PAGO_CODIGO = "SP_SELECCIONAR_PAGO_POR_CODIGO";
    // private static final String PAGOS_HISTORICOS="SP_PAGOS_HISTORICOS";
    private static final String PAGOS_HISTORICOS = "SELECT sistemaplanilla.pago.salarioBase,sistemaplanilla.pago.bonos,sistemaplanilla.pago.deducciones,sistemaplanilla.pago.prestamos,sistemaplanilla.pago.extras,sistemaplanilla.pago.tardias,sistemaplanilla.pago.feriadosPago,sistemaplanilla.pago.vacionesPago,sistemaplanilla.pago.adelantoAguinaldo,sistemaplanilla.pago.aguinaldo FROM sistemaplanilla.pago INNER JOIN sistemaplanilla.empleado ON sistemaplanilla.pago.numEmpleado=sistemaplanilla.empleado.numEmpleado WHERE sistemaplanilla.pago.fechaPagoInicio>=:fechaInicio AND sistemaplanilla.pago.fechaPagoFin<=:fechaFin AND sistemaplanilla.pago.numEmpleado=:num AND sistemaplanilla.empleado.fechaFin is not null";
    private static final String GENERAR_PLANILLA="SP_GENERAR_PLANILLA";
    public static GestorPago obtenerInstancia() {
        if (instancia == null) {
            instancia = new GestorPago();
        }
        return instancia;
    }

    private GestorPago() {
    }

    /*@Override
     public Object insertar(Object pago) {
     long numEmpleado = 0;//si solo retorna 0 entonces hubo un error
     try {
     iniciaOperacion();
     Object verificacionPago = sesion.createQuery("from Pago where codigo= :? AND fechaPagoInicio = :inicio AND fechaPagoFin = :fin ")
     .setParameter("?", ((Pago) pago).getId())
     .setParameter("inicio", ((Pago) pago).getId().getFechaPagoInicio())
     .setParameter("fin", ((Pago) pago).getId().getFechaPagoFin())
     .uniqueResult();
     if (verificacionPago == null) {
     numEmpleado = (long) sesion.save(pago);
     tx.commit();
     } else {
     return -2;//El codigo ya esta ocupado
     }
     } catch (HibernateException he) {
     manejaExcepcion(he);
     } finally {
     sesion.close();
     }

     return numEmpleado;
     }*/
    public Object insertarAguinaldo(Aguinaldo aguinaldo) {
        AguinaldoId exito = null;
        try {
            iniciaOperacion();
            Object verificacion = sesion.createQuery("from Aguinaldo where numEmpleado=:num AND fecha=:date")
                    .setParameter("num", aguinaldo.getId().getNumEmpleado())
                    .setParameter("date", aguinaldo.getId().getFecha())
                    .uniqueResult();
            if (verificacion == null) {
                exito = (AguinaldoId) sesion.save(aguinaldo);
                tx.commit();
            } else {
                return null;//El codigo ya esta ocupado
            }
        } catch (HibernateException he) {
            exito = null;
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
            manejaExcepcion(he);
        } finally {
            sesion.close();
        }

        return exito;
    }

    public Object insertarAsignacionDeduccion(Object asignarDeduccion) {
        boolean exito = false;//si solo retorna 0 entonces hubo un error
        try {
            iniciaOperacion();
            sesion.save(asignarDeduccion);
            exito = true;
            tx.commit();

        } catch (HibernateException he) {
            exito = false;
            manejaExcepcion(he);
        } finally {
            sesion.close();
        }

        return exito;
    }

    /*public Object insertarAsignacionPrestamo(Object asignarPrestamo) {
     long codigo = 0;//si solo retorna 0 entonces hubo un error
     try {
     iniciaOperacion();
     Object verificarAsignacion = sesion.createQuery("from asignardeduccion where codigo= :? AND fechaPagoInicio = :? AND fechaPagoFin = :?  AND numeroEmpleado = :?")
     .setParameter("?", ((Asignarprestamo) asignarPrestamo).getId())
     .setParameter("?", ((Asignarprestamo) asignarPrestamo).getId().getFechaPagoInicio())
     .setParameter("?", ((Asignarprestamo) asignarPrestamo).getId().getFechaPagoFin())
     .setParameter("?", ((Asignarprestamo) asignarPrestamo).getId().getNumEmpleado())
     .uniqueResult();
     if (verificarAsignacion == null) {
     codigo = (long) sesion.save(asignarPrestamo);
     tx.commit();
     } else {
     return -2;//El codigo ya esta ocupado
     }
     } catch (HibernateException he) {
     manejaExcepcion(he);
     } finally {
     sesion.close();
     }

     return codigo;
     }*/
    private ArrayList<Pago> getListaGenericaPagos(String procedimiento, ArrayList<Object> parametros) throws HibernateException {

        ArrayList<Pago> pagos = new ArrayList<>();
        try {
            ResultSet rs = llamarProcedimientoAlmacenado(procedimiento, parametros);
            int maxCols = rs.getMetaData().getColumnCount();
            while (rs.next()) {
                ArrayList<Object> registro = new ArrayList<>(maxCols);
                for (int i = 0; i < maxCols; i++) {
                    registro.add(rs.getObject(i + 1));
                }
                pagos.add(Pago.fromArray(registro));
            }

        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | SQLException e) {
            System.out.println(e.getMessage());
        } finally {
        }
        return pagos;
    }

    public ArrayList<Pago> getPagosDeduccionesPorCodigo(long codigo, Date fechaPagoInicio, Date fechaPagoFin) throws HibernateException {

        ArrayList<Object> parametros = new ArrayList<>();
        parametros.add(codigo);
        parametros.add(fechaPagoInicio);
        parametros.add(fechaPagoFin);
        return getListaGenericaPagos(PAGO_CODIGO, parametros);
    }

    public ArrayList<Pago> getPagosPorCedula(long cedula, Date fechaPagoInicio, Date fechaPagoFin) throws HibernateException {
        ArrayList<Object> parametros = new ArrayList<>();
        parametros.add(cedula);
        parametros.add(fechaPagoInicio);
        parametros.add(fechaPagoFin);
        return getListaGenericaPagos(PAGO_CEDULA, parametros);
    }

    public ArrayList<Pago> getPagosHistoricos(long numEmpleado, Date fechaPagoInicio, Date fechaPagoFin) throws HibernateException {
        ArrayList<Pago> lista = new ArrayList<Pago>();
        try {
            iniciaOperacion();
            Criteria cr = sesion.createCriteria(Pago.class);
            Criterion fechaInicio = Restrictions.between("id.fechaPagoInicio", fechaPagoInicio, fechaPagoFin);
            Criterion fechaFin = Restrictions.between("id.fechaPagoFin", fechaPagoInicio, fechaPagoFin);
            Criterion codigo = Restrictions.eq("id.numEmpleado", numEmpleado);
            LogicalExpression andExp = Restrictions.and(fechaInicio, fechaFin);
            cr.add(andExp);
            cr.add(codigo);
            lista = (ArrayList<Pago>) cr.list();
        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
            manejaExcepcion(he);
        } finally {
            sesion.close();
        }
        return lista;

    }

    public Pago getPagoPorCedula(long numeroEmpleado, Date fechaPagoInicio, Date fechaPagoFin) {
        Pago pago = null;
        try {
            iniciaOperacion();
            pago = (Pago) sesion.createQuery("from Pago where numEmpleado=:empleado AND fechaPagoInicio=:inicio AND fechaPagoFin=:fin")
                    .setParameter("empleado", numeroEmpleado)
                    .setParameter("inicio", fechaPagoInicio)
                    .setParameter("fin", fechaPagoFin)
                    .uniqueResult();

        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
            manejaExcepcion(he);
        } finally {
            sesion.close();
        }

        return pago;
    }

    public ArrayList<Pago> getPagosPorNumEmpleado(long numEmpleado) {
        ArrayList<Pago> pagos = new ArrayList<Pago>();
        try {
            iniciaOperacion();
            pagos = (ArrayList<Pago>) sesion.createSQLQuery("SELECT * FROM Pago WHERE numEmpleado=:? order by fechaPagoFin desc LIMIT 12")
                    .addEntity(Pago.class)
                    .setParameter("?", numEmpleado)
                    .list();
        } finally {
            sesion.close();
        }
        return pagos;
    }

    public ArrayList<Pago> getPagoEmpleado(long numEmpleado) {
        ArrayList<Pago> pagos = null;
        try {
            iniciaOperacion();
            pagos = (ArrayList<Pago>) sesion.createSQLQuery("SELECT * FROM pago WHERE numEmpleado=:? ")
                    .addEntity(Pago.class)
                    .setParameter("?", numEmpleado)
                    .list();

        } finally {
            sesion.close();
        }
        return pagos;
    }

    public ArrayList<Liquidacion> obtenerListaLiquidaciones() throws HibernateException {
        ArrayList<Liquidacion> lista = null;

        try {
            iniciaOperacion();
            lista = (ArrayList<Liquidacion>) sesion.createQuery("from Liquidacion").list();
        } finally {
            sesion.close();
        }

        return lista;
    }

    public ArrayList<Aguinaldo> obtenerListaAguinaldos() throws HibernateException {
        ArrayList<Aguinaldo> lista = null;
        try {
            iniciaOperacion();
            lista = (ArrayList<Aguinaldo>) sesion.createSQLQuery("SELECT * FROM Aguinaldo WHERE MONTH(aguinaldo.fecha)=MONTH(CURDATE())")
                    .addEntity(Aguinaldo.class)
                    .list();
        } finally {
            sesion.close();
        }
        return lista;
    }

    public int getCantHorasExtras(long numEmpleado, Date fechaPagoInicio, Date fechaPagoFin) {
        int cantidad = 0;
        try {
            iniciaOperacion();
            cantidad = ((java.math.BigDecimal) sesion.createSQLQuery("select IFNULL(sum(hora_extra.horas),0) as cantidadHoras from hora_extra where numEmpleado=:empleado and fecha between :inicio and :fin")
                    .setLong("empleado", numEmpleado)
                    .setDate("inicio", fechaPagoInicio)
                    .setDate("fin", fechaPagoFin)
                    .uniqueResult()).intValue();

        } catch (HibernateException he) {
            System.out.println(he.getCause());
            System.out.println(he.getMessage());
            manejaExcepcion(he);
        } catch (Exception e) {
            System.out.println(e.getCause());
            System.out.println(e.getMessage());

        } finally {
            sesion.close();
        }

        return cantidad;
    }
    public boolean generarPlanilla(){
        boolean exito=false;
        try {
            
            this.llamarProcedimientoAlmacenado(GENERAR_PLANILLA, null);
            exito=true;
        } catch (SQLException ex) {
            System.out.println(ex.getCause());
            System.out.println(ex.getMessage());
            exito=false;
        } catch (ClassNotFoundException ex) {
            System.out.println(ex.getCause());
            System.out.println(ex.getMessage());
            exito=false;
        } catch (IllegalAccessException ex) {
             System.out.println(ex.getCause());
            System.out.println(ex.getMessage());
            exito=false;
        } catch (InstantiationException ex) {
            System.out.println(ex.getCause());
            System.out.println(ex.getMessage());
            exito=false;
           
        }
        return exito;
    }
}
